﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

using alib.Debugging;
using alib.Enumerable;
using alib.Collections;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public interface IRenderNode
	{
	};

	public interface ILabelRenderNode : IRenderNode
	{
		String Label { get; }
	};

	public interface ICorefRenderNode : IRenderNode
	{
		String CorefTag { get; }
	};

	public interface ILabeledFeatureValueNode : ILabelRenderNode
	{
		IRenderNode LabeledNode { get; }
	};

	public interface IListRenderNode<out T> : IRenderNode
		where T : IRenderNode
	{
		IEnumerable<T> ListNodes { get; }
	};

	public interface IListRenderNode : IListRenderNode<IRenderNode>
	{
	};

	public interface IFeatValueRenderNode : ILabelRenderNode, ICorefRenderNode
	{
		IEnumerable<IRenderPairs> FeatValuePairs { get; }
	};

	public interface IRenderPairs : ILabeledFeatureValueNode
	{
		bool IsCoreferenced { get; }
		//bool IsMasterCoref { get; }
		bool IsMaximal { get; }
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public abstract class LabelValueNode : ILabelRenderNode
	{
		public LabelValueNode(String s_label)
		{
			this.s_label = s_label;
		}
		String s_label;
		public String Label { get { return s_label; } }
	};

	public abstract class CorefValueNode : LabelValueNode, ICorefRenderNode
	{
		public CorefValueNode(String s, String s_coref)
			: base(s)
		{
			this.s_coref = s_coref;
		}
		String s_coref;
		public String CorefTag { get { return s_coref; } }
	};


	public class StringValueNode : CorefValueNode
	{
		public StringValueNode(String s, String s_coref)
			: base(s, s_coref)
		{
		}
	};

	public class AtomicValueNode : CorefValueNode
	{
		public AtomicValueNode(Type t, String s_coref)
			: base(t.Name, s_coref)
		{
			this.t = t;
		}
		agree.Type t;
	};

	public class IntegerValueNode : CorefValueNode
	{
		public IntegerValueNode(int i, String s_coref)
			: base(i.ToString(), s_coref)
		{
			this.i = i;
		}
		int i;
	};

	public class SkolValueNode : CorefValueNode
	{
		public SkolValueNode(String s_label, String s_coref)
			: base(s_label, s_coref)
		{
		}
	};

	public class LabeledFeatValueNode : LabelValueNode, ILabeledFeatureValueNode
	{
		public LabeledFeatValueNode(String s_label, IRenderNode rn)
			: base(s_label)
		{
			this.rn = rn;
		}
		protected IRenderNode rn;
		public IRenderNode LabeledNode { get { return rn; } }
	};

	[DebuggerDisplay(" {rn==null ? \"null\" : rn.GetType().Name,nq} {s_label,nq} {rn==null ? \"null\" : rn.ToString(),nq}")]
	public class FeatureValueNode : LabeledFeatValueNode, IRenderPairs
	{
		public FeatureValueNode(String Feature, IRenderNode rn, bool f_maximal)
			: base(Feature, rn)
		{
			this._f_maximal = f_maximal;
			//this._f_master = f_master;
		}

		bool _f_maximal;
		public bool IsMaximal { get { return _f_maximal; } }

		//public bool _f_master;
		//public bool IsMasterCoref { get { return _f_master; } }

		public bool IsCoreferenced
		{
			get
			{
				ICorefRenderNode icrn = rn as ICorefRenderNode;
				return icrn != null && icrn.CorefTag != null;
			}
		}
	};

	public abstract class lrn_base<T> : IListRenderNode<T>
		where T : IRenderNode
	{
		public lrn_base(IEnumerable<T> rgrn)
		{
			this.rgrn = rgrn as T[] ?? rgrn.ToArray();
		}
		T[] rgrn;

		public IEnumerable<T> ListNodes { get { return rgrn; } }
	};

	public class ListValueNode : lrn_base<IRenderNode>, IListRenderNode
	{
		public static readonly ListValueNode Empty = new ListValueNode(Collection<IRenderNode>.None);

		public ListValueNode(IEnumerable<IRenderNode> rgrn)
			: base(rgrn)
		{
		}
	};

	public class DiffListValueNode : lrn_base<IListRenderNode>, ICorefRenderNode
	{
		public DiffListValueNode(AdeptFeatValueRenderNode ts, String s_coref)
			: base(PartitionDiffList(ts))
		{
			this.s_coref = s_coref;

			int i_feat = ts.im.f_ix_dlist_last;
			Edge e;
			this.last = ts.Tfs.TryGetEdge(i_feat, ts.out_mark, out e) ?
				ts.GetValueNode(i_feat, e) :
				ListValueNode.Empty;
		}

		String s_coref;
		public String CorefTag { get { return s_coref; } }
		public IRenderNode last;

		static IEnumerable<IListRenderNode> PartitionDiffList(AdeptFeatValueRenderNode ts_first)
		{
			var rgts = ts_first
						.DiffListListSlots()
						.Select(ts => new AdeptFeatValueRenderNode(ts_first, ts.ix1))
						.ToArray();

			if (rgts.Length > 0)
			{
				IRenderNode[] sect;
				for (int i = 0; (sect = rgts.Skip(i)
											.TakeWhile((ts, ix) => ix == 0 || ts.in_mark > 0)
											.ToArray()).Length > 0; i += sect.Length)
					yield return new ListValueNode(sect);
			}
		}
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// IRenderNode implementations which reference a live tfs
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class AdeptRenderNode : TfsSlotRef, ICorefRenderNode, ILabelRenderNode
	{
		public AdeptRenderNode(AdeptRenderNode rn_root, int ix1)
			: base(rn_root.Tfs, ix1)
		{
			this.corefs = rn_root.corefs;
		}
		protected AdeptRenderNode(ITfsSlot ts)
			: base(ts)
		{
			this.corefs = new ReentrancyFinder(ts);
		}
		public ReentrancyFinder corefs;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public String CorefTag
		{
			get
			{
				ReentrancyFinder.Entry rev;
				var e = this.Edge();
				return e.FlagsId < 0 && corefs.TryGetValue(e, out rev) ? rev.i_tag.ToString() : null;
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public String Label
		{
			get
			{
				var e = this.Edge();
				String s = tu.TypeNameOrStringValue(e.FlagsId);
				if (e.FlagsId.IsStringValue())
					s = alib.String._string_ext.DoubleQuote(s);
				return s;
			}
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class AdeptFeatValueRenderNode : AdeptRenderNode, IFeatValueRenderNode
	{
		public AdeptFeatValueRenderNode(AdeptRenderNode rn_root, int ix1)
			: base(rn_root, ix1)
		{
		}
		protected AdeptFeatValueRenderNode(ITfsSlot ts)
			: base(ts)
		{
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public IEnumerable<IRenderPairs> FeatValuePairs
		{
			get
			{
				var ef = this.FlagsId();
				if ((ef & agree.Edge.Flag.EtmNonBareType) == 0)
					return Collection<IRenderPairs>.None;

				var ftm = base.Tfs.ftm;
				return ftm.rgrgfix_by_type[(int)(ef & Edge.Flag.MultiIdMask)]
								.Sort(ftm.FeatureDisplayOrderComparer)
								.SelectNotNull(ifeat => GetFeatValueNode(i_feat));
			}
		}

		public FeatureValueNode GetFeatValueNode(int i_feat)
		{
			Edge ne;
			if (!base.Tfs.TryGetEdge(i_feat, this.out_mark(), out ne))
				return null;

			//ReentrancyFinder.Entry rev;
			//bool f_master = ne.FlagsId < 0 && Tfs.Reentrancies(ctx).TryGetValue(ne, out rev) &&
			//	fi.i_feat == rev.cref_display.i_feat && this.out_mark == rev.cref_display.Host.Mark;

			IRenderNode rn = GetValueNode(i_feat, ne);

			FeatureInfo fi = ftm[i_feat];
			bool f_maximal = fi.introduced_by == this.Type();
			return new FeatureValueNode(fi.feature.ToUpper(), rn, f_maximal);
		}

		public IRenderNode GetValueNode(int i_feat, Edge ne)
		{
			var tfs = base.Tfs;
			String val;

			ReentrancyFinder.Entry rev;
			String sct = ne.FlagsId < 0 && corefs.TryGetValue(ne, out rev) ? rev.i_tag.ToString() : null;

			if (i_feat == im.f_ix_dlist_list)
				return new DiffListValueNode(this, sct);

			if (ne.FlagsId.IsSkolemValue())
				return new SkolValueNode(TypeUtils.GetSkolemString(ne.FlagsId), sct);

			if (ne.FlagsId.IsIntegerValue())
				return new IntegerValueNode(ne.FlagsId.GetIntegerValue(), sct);

			//if ((val = tu.GetStringValue(ne.FlagsId)) != null)
			//	return new StringValueNode( val.DoubleQuote(), sct);

			int ix1 = tfs.GetEdgeIndex(i_feat, this.out_mark());

			if ((val = tu.GetStringValue(ne.FlagsId)) != null)
				return new AdeptRenderNode(this, ix1);

			if ((ne.FlagsId & Edge.Flag.EtmNonBareType) == 0)
				return new AtomicValueNode(tfs.tu.GetEdgeType(ne.FlagsId), sct);

			return new AdeptFeatValueRenderNode(this, ix1);
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class RootRenderNode : AdeptFeatValueRenderNode
	{
		public RootRenderNode(ITfsSlot ts)
			: base(ts)
		{
		}
	};

}
